package gui.inventory;

import static org.junit.Assert.*;

import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;

import gui.item.ItemData;
import gui.product.ProductData;

import org.junit.Before;
import org.junit.Test;

import persistence.DataPersistor;

import common.util.DateUtils;

import core.Container;
import core.ContainerFacade;
import core.Item;
import core.ItemFacade;
import core.Product;
import core.ProductFacade;
import core.ProductGroup;
import core.RootStorageUnit;
import core.SerializableSaver;
import core.StorageUnit;
import core.exception.IllegalAddException;
import core.exception.IllegalEditException;
import core.exception.IllegalRemoveException;
import core.exception.ModelException;
import core.exception.NotFoundException;
import core.exception.SaveException;

public class InventoryControllerTest implements IInventoryView{
	
	private ProductContainerData _root;
	private ProductContainerData _selectedContainer;
	
	private ItemData[] _items;
	private ItemData _selectedItem;
	
	private ProductData[] _products;
	private ProductData _selectedProduct;
	
	private String _contextSU;
	private String _contextPG;
	private String _contextSupply;
	
	private String _name;
	private String _amount;
	private String _unit;
	private String _barcode;
	private boolean _cancel;
	
	private InventoryController _controller;

	@Before
	public void setUp() throws Exception {
		DataPersistor.instance().init("-serial");		
		ContainerFacade.clearAllData();
		ProductFacade.clearAllData();
		ItemFacade.clearAllData();

		// Initial container tree:
		// RootStorageUnit
		//		Apple
		//			Banana
		//			Candy
		//		Dates
		Container apple = ContainerFacade.instance().addStorageUnit("Apple");
		ContainerFacade.instance().addProductGroup(apple, "Banana", "0", "count");
		ContainerFacade.instance().addProductGroup(apple, "Candy", "4.32", "fluid ounces");
		ContainerFacade.instance().addStorageUnit("Dates");
		
		// where there are two products in the system
		// 1234 sweets
		// 3333 sours
		ProductFacade.instance().addProduct(new Product("1234", "sweets", "4", "gallons", 4, 3));
		ProductFacade.instance().addProduct(new Product("3333", "sours", "1", "count", 2, 0));
		
		// and there are 2 items of each product, both in Apple.
		ItemFacade.instance().addItem(ProductFacade.instance().getProduct("1234"), apple);
		ItemFacade.instance().addItem(ProductFacade.instance().getProduct("1234"), apple);
		
		ItemFacade.instance().addItem(ProductFacade.instance().getProduct("3333"), apple);
		ItemFacade.instance().addItem(ProductFacade.instance().getProduct("3333"), apple);
		
		SerializableSaver _saver = new SerializableSaver();
		try 
		{
			_saver.save();
		} 
		catch (IOException e) 
		{
			fail("not good");
		}		
		// member initialization
		_root = null;
		_selectedContainer = null;		
		
		_items = null;
		_selectedItem = null;
		
		_products = null;
		_selectedProduct = null;
		
		_contextSU = null;
		_contextSupply = null;
		_contextPG = null;
		
		_name = null;
		_amount = null;
		_unit = null;
		_barcode = null;
		_cancel = false;
		
		_controller = new InventoryController(this);
		ContainerFacade.instance().addControllerForTest(_controller);
		ProductFacade.instance().addControllerForTest(_controller);
		ItemFacade.instance().addControllerForTest(_controller);
		
		validateCurrentState();
		
	}


	@Test
	public void testDeleteStorageUnit() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		assertFalse(_controller.canDeleteStorageUnit());
		
		_selectedContainer = _root.getChild(1);
		assertTrue(_controller.canDeleteStorageUnit());
		
		_controller.deleteStorageUnit();
		validateCurrentState();
		assertNull("no container should be selected after delete",_selectedContainer);

		// for the bug with not being allowed to add a storage unit with name that was deleted
		_name = "Dates";
		_selectedContainer = _root;
		_controller.addStorageUnit();
		validateCurrentState();
		assertEquals("Should select newly created","Dates",_selectedContainer.getName());
	}

	@Test
	public void testDeleteProductGroup() throws IllegalAddException, NotFoundException, 
		SaveException {
		// first, expand our tree a bit
		_selectedContainer = _root.getChild(0).getChild(0);
		
		_name = "hasitems";
		_amount = "0";
		_unit = "count";
		_controller.addProductGroup();
		
		_name = "subchild";
		_controller.addProductGroup();
		ItemFacade.instance().moveItem(ItemFacade.instance().getItem("400000000008"), 
				_root.getChild(0).getChild(0).getChild(0).getContainer());
		
		// make delete subchild
		assertTrue(_controller.canDeleteProductGroup());
		_controller.deleteProductGroup();
		validateCurrentState();
		assertNull(_selectedContainer);
		
		_selectedContainer = _root.getChild(0).getChild(0).getChild(0);
		assertFalse(_controller.canDeleteProductGroup());
	}

	@Test
	public void testSelectionChanged() throws NotFoundException {
		_selectedContainer = null;
		_controller.productContainerSelectionChanged();
		validateCurrentState();
		
		_selectedContainer = _root;
		_controller.productContainerSelectionChanged();
		validateCurrentState();
		
		selectAllProductsAndItems();
		
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		validateCurrentState();
		
		selectAllProductsAndItems();	
		
		_selectedContainer = _root.getChild(1);
		_controller.productContainerSelectionChanged();
		validateCurrentState();
		
		selectAllProductsAndItems();	
		
		_selectedContainer = _root.getChild(0).getChild(0);
		_controller.productContainerSelectionChanged();
		validateCurrentState();
		
		selectAllProductsAndItems();		
	}


	public void selectAllProductsAndItems() throws NotFoundException {
		for (int i = 0; i < _products.length; i++){
			_selectedProduct = _products[i];
			_controller.productSelectionChanged();
			validateCurrentState();
			
			for (int j=0; j < _items.length; j++){
				_selectedItem = _items[j];
				_controller.itemSelectionChanged();
				validateCurrentState();
			}
		}
		_selectedProduct =null;
		_selectedItem = null;
	}

	@Test
	public void testDeleteProduct() throws NotFoundException {
		// remove items for this product
		testRemoveItem();
		
		ProductData removed = _selectedProduct;
		
		// remove product from container
		assertTrue(_controller.canDeleteProduct());
		_controller.deleteProduct();
		validateCurrentState();
		assertNull(_selectedProduct);
		assertNull(_selectedItem);
		assertEquals(_root.getChild(0),_selectedContainer);
		
		// select the root
		_selectedContainer = _root;
		_controller.productContainerSelectionChanged();
		validateCurrentState();
		
		// reselect the product. 
		assertTrue(Arrays.asList(_products).contains(removed));
		_selectedProduct = removed;
		_controller.productSelectionChanged();
		validateCurrentState();
		
		// It should have no items, so should be removable
		assertTrue(_controller.canDeleteProduct());
		
		// test system purge
		_controller.deleteProduct();
		validateCurrentState();
		assertNull(_selectedProduct);
		assertNull(_selectedItem);
		assertEquals(_root,_selectedContainer);
		
	}

	@Test
	public void testEditItem() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		_selectedProduct = _products[0];
		ProductData product = _selectedProduct;
		_controller.productSelectionChanged();
		_selectedItem = _items[0];
		ItemData selected = _selectedItem;
		
		_controller.editItem();
		validateCurrentState();
		assertEquals("Selection should remain",selected,_selectedItem);
		assertEquals("Selection should remain",_root.getChild(0),_selectedContainer);
		assertEquals("Selection should remain", product, _selectedProduct);
		
		_cancel = true;
		_controller.editItem();
		validateCurrentState();
		assertEquals("Selection should remain",selected,_selectedItem);
		assertEquals("Selection should remain",_root.getChild(0),_selectedContainer);
		assertEquals("Selection should remain", product, _selectedProduct);		
	}

	@Test
	public void testRemoveItem() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		
		_selectedProduct = _products[0];
		_controller.productSelectionChanged();
		
		_selectedItem = _items[0];
		_controller.removeItem();
		validateCurrentState();
		assertNull(_selectedItem);
		assertEquals(_root.getChild(0), _selectedContainer);
		assertEquals(_products[0], _selectedProduct);
		
		// do it twice so we can call this before deleting the product
		_selectedItem = _items[0];
		_controller.removeItem();
		validateCurrentState();
		assertNull(_selectedItem);
		assertEquals(_root.getChild(0), _selectedContainer);
		assertEquals(_products[0], _selectedProduct);		
		
	}

	@Test
	public void testAddProductGroup() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		
		// add child in beginning (also test name same as storage unit)
		_name = "Apple";
		_unit = "fluid ounces";
		_amount = "4.6";
		assertTrue(_controller.canAddProductGroup());
		_controller.addProductGroup();
		validateCurrentState();
		assertEquals("Should select newly created","Apple",_selectedContainer.getName());
		
		// add child in middle
		_selectedContainer = _root.getChild(0);
		_name = "BB";
		assertTrue(_controller.canAddProductGroup());
		_controller.addProductGroup();
		validateCurrentState();
		assertEquals("Should select newly created","BB",_selectedContainer.getName());
	
		// add child at end
		_selectedContainer = _root.getChild(0);
		_name = "ZZ";
		assertTrue(_controller.canAddProductGroup());
		_controller.addProductGroup();
		validateCurrentState();
		assertEquals("Should select newly created","ZZ",_selectedContainer.getName());

		// add nested child
		assertTrue(_controller.canAddProductGroup());
		_controller.addProductGroup();
		validateCurrentState();
		assertEquals("Should select newly created","ZZ",_selectedContainer.getName());

		// cancel
		ProductContainerData selected = _selectedContainer;
		_cancel = true;
		_controller.addProductGroup();
		validateCurrentState();
		assertEquals("Should select newly created",selected,_selectedContainer);
		
		
	}

	@Test
	public void testAddItems() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		_selectedProduct = _products[0];
		ProductData selected = _selectedProduct;
		
		// add an item of the selected product
		_controller.addItems();
		validateCurrentState();
		assertEquals("product selection should stay the same",selected,_selectedProduct);
		assertEquals("container selection should stay the same",
				_root.getChild(0),_selectedContainer);
		
		// no items added
		_cancel = true;
		_controller.addItems();
		validateCurrentState();
		assertEquals("product selection should stay the same",selected,_selectedProduct);
		assertEquals("container selection should stay the same",
				_root.getChild(0),_selectedContainer);
		
		// new product created
		_cancel = false;
		_name = "treats";
		_barcode = "666";
		_controller.addItems();
		validateCurrentState();
		assertEquals("product selection should stay the same",selected,_selectedProduct);
		assertEquals("container selection should stay the same",
				_root.getChild(0),_selectedContainer);		
	}

	@Test
	public void testTransferItems() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		
		_selectedProduct= _products[1];
		_controller.productSelectionChanged();
		
		_controller.addProductToContainer(_selectedProduct, _root.getChild(1));
		
		_selectedContainer = _root.getChild(1);
		_controller.productContainerSelectionChanged();
		
		_selectedProduct = _products[0];
		assertNotNull(_selectedProduct);
		_controller.productSelectionChanged();
		
		_controller.transferItems();
		validateCurrentState();
	}

	@Test
	public void testRemoveItems() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		
		_selectedProduct= _products[0];
		_controller.productSelectionChanged();
		
		_controller.removeItems();
		validateCurrentState();
	}

	@Test
	public void testAddStorageUnit() throws NotFoundException {
		_selectedContainer = _root;
		assertTrue(_controller.canAddStorageUnit());
		
		// insert name in middle
		_name = "Bear";
		_controller.addStorageUnit();
		validateCurrentState();
		assertEquals("Should select new su on creation","Bear",_selectedContainer.getName());

		// insert name at beginning
		_name = "AA";
		_controller.addStorageUnit();
		validateCurrentState();
		assertEquals("Should select new su on creation","AA",_selectedContainer.getName());

		// insert name at end
		_name = "ZZ";
		_controller.addStorageUnit();
		validateCurrentState();
		assertEquals("Should select new su on creation","ZZ",_selectedContainer.getName());
		
		_cancel = true;
		_name = "fudge";
		_selectedContainer = _root;
		_controller.productContainerSelectionChanged();
		_controller.addStorageUnit();
		validateCurrentState();
		assertEquals("Should not change selection",_root,_selectedContainer);
		
	}

	@Test
	public void testEditProductGroup() throws NotFoundException {
		_selectedContainer = _root.getChild(0).getChild(1);
		ProductContainerData selected = _selectedContainer;
		assertEquals("make sure I grabbed what I thought I grabbed","Candy",
				_selectedContainer.getName());
		
		// edit to beginning
		_name = "Apple";
		_amount = "88";
		_unit = "quarts";
		assertTrue(_controller.canEditProductGroup());
		_controller.editProductGroup();
		validateCurrentState();
		assertEquals("Should stay selected",selected,_selectedContainer);
		
		// edit back to end
		_name = "ZZ";
		_amount = "48";
		_unit = "pints";
		assertTrue(_controller.canEditProductGroup());
		_controller.editProductGroup();
		validateCurrentState();
		assertEquals("Should stay selected",selected,_selectedContainer);
		
		_cancel = true;
		_name = "bob";
		assertTrue(_controller.canEditProductGroup());
		_controller.editProductGroup();
		validateCurrentState();
		assertEquals("Should stay selected",selected,_selectedContainer);
		
	}

	@Test
	public void testEditStorageUnit() throws NotFoundException {
		ProductContainerData tempSelect = _root.getChild(0);
		_selectedContainer = _root.getChild(0);
		assertEquals("Just checking I got the child I thought I got","Apple",
				_selectedContainer.getName());
		
		assertTrue(_controller.canEditStorageUnit());
		
		_name = "ZZ";
		_controller.editStorageUnit();
		validateCurrentState();
		assertEquals("Should not lose selection",_selectedContainer,tempSelect);
	
		_cancel = true;
		_controller.editStorageUnit();
		validateCurrentState();
		assertEquals("Should not lose selection",_selectedContainer,tempSelect);
	
	}

	@Test
	public void testEditProduct() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		
		_selectedProduct = _products[0];
		_controller.productSelectionChanged();
		
		_controller.editProduct();
		validateCurrentState();
		assertEquals(_products[0],_selectedProduct);
		
		_cancel = true;
		_controller.editProduct();
		validateCurrentState();
		assertEquals(_products[0],_selectedProduct);		
	}

	@Test
	public void testAddProductToContainer() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		
		_selectedProduct = _products[0];
		_controller.productSelectionChanged();
		
		validateCurrentState();
		
		// add within storage unit
		_controller.addProductToContainer(_selectedProduct, _root.getChild(0).getChild(0));
		validateCurrentState();
		assertEquals(_root.getChild(0),_selectedContainer);
		assertFalse(Arrays.asList(_products).contains(_selectedProduct));
		
		// add outside storage unit
		_selectedProduct = _products[0];
		_controller.productSelectionChanged();
		
		_controller.addProductToContainer(_selectedProduct, _root.getChild(0).getChild(0));
		validateCurrentState();
		assertEquals(_root.getChild(0),_selectedContainer);
		assertFalse(Arrays.asList(_products).contains(_selectedProduct));	
	
	}

	@Test
	public void testMoveItemToContainer() throws NotFoundException {
		_selectedContainer = _root.getChild(0);
		_controller.productContainerSelectionChanged();
		
		_selectedProduct = _products[0];
		_controller.productSelectionChanged();
		
		// move within storage unit
		_controller.moveItemToContainer(_items[0], _root.getChild(0).getChild(0));
		validateCurrentState();
		
		// move outside of storage unit
		assertEquals(1,_products.length);
		_selectedProduct = _products[0];
		_controller.productSelectionChanged();
		_controller.moveItemToContainer(_items[0], _root.getChild(1));
		validateCurrentState();
		assertEquals(1,_products.length);
		assertEquals(1,_items.length);		
		
	}
	
	public void validateCurrentState() throws NotFoundException {
		validateContainers();		
		validateProducts();
		validateItems();
	}

	// These functions validate the current state of the view.
	public void validateProducts() {
		HashSet<Product> expectedProducts = new HashSet<Product>();
		Iterator<Product> iter = null;
		if (_selectedContainer != null){
			// get iter
			if (_selectedContainer.getContainer() instanceof RootStorageUnit)
				iter = ProductFacade.instance().getAllProducts();
			else{
				iter = _selectedContainer.getContainer().getProducts();
			}
			
			// build set
			if (iter != null){
				while (iter.hasNext()){
					expectedProducts.add(iter.next());
				}		
			 }			
		}

		if (_products == null){
			assert(expectedProducts.isEmpty());
			return;
		}
		
		
		ProductData selected = _selectedProduct;
		for(int i=0; i < _products.length; i++){
			_selectedProduct = _products[i];
			
			// context menu checks
			assertTrue("Products are always editable",_controller.canEditProduct());
			assertEquals("Deletion should match model",_controller.canDeleteProduct(), 
					ProductFacade.instance().canRemoveProduct(
							_selectedProduct.getProduct(), _selectedContainer.getContainer()));
			validateProductData(_selectedProduct);
			assertTrue("Products belong to selected container",
					expectedProducts.contains(_selectedProduct.getProduct()));
			expectedProducts.remove(_selectedProduct.getProduct());
		}
		
		assertTrue("All expected products should be present",expectedProducts.isEmpty());
		
		// check for null
		_selectedProduct = null;
		assertFalse(_controller.canEditProduct());
		assertEquals(_controller.canDeleteProduct(), false);

		_selectedProduct = selected;
	}
	
	private void validateProductData(ProductData data){
		assertEquals("Barcode matches", data.getProduct().getBarcode().toString(), 
				data.getBarcode());
		assertEquals("Description matches",data.getProduct().getDescription(), 
				data.getDescription());
		assertEquals("Size unit matches",data.getProduct().getUnitOfMeasurement(), 
				data.getSizeUnit());
		assertEquals("Size quantity matches",
				data.getProduct().getQuantityForOneUnit(), 
				Float.parseFloat(data.getSizeValue()),0.1);
		assertEquals("Shelf life matches",Integer.toString(data.getProduct().getShelfLife()) 
				+" months", data.getShelfLifeSting());
		assertEquals("3 month supply matches",Integer.toString(
				data.getProduct().getThreeMonthSupply()) + " count",data.getSupplyString());
		if (!(_selectedContainer.getContainer() instanceof RootStorageUnit))
			assertEquals("Count is correct",Integer.toString(ItemFacade.instance()
					.getNumItemsInProductAndContainer(data.getProduct(),
							_selectedContainer.getContainer())),
					data.getCount());
		else
			assertEquals("Count is correct",
					Integer.toString(ItemFacade.instance().
							getNumberOfItemsInProduct(data.getBarcode())),
					data.getCount());
	}
	
	public void validateItems() throws NotFoundException{
		if (_selectedProduct == null || _selectedContainer == null){
			assert(_items == null || _items.length == 0);
			return;
		}
		
		TreeSet<Item> expectedItems = new TreeSet<Item>();
		Iterator<Item> iter;
		if (!(_selectedContainer.getContainer() instanceof RootStorageUnit))
			 iter = ItemFacade.instance().getItemsInProductAndContainer(
					_selectedProduct.getProduct(), _selectedContainer.getContainer());
		else
			try{
				iter = ItemFacade.instance().getItemsInProduct(_selectedProduct.getBarcode());
			} catch (NotFoundException e) {iter = null;}
		
		if (iter != null){
			while (iter.hasNext()){
				expectedItems.add(iter.next());
			}
		}
		
		ItemData selected = _selectedItem;
		for (int i=0; i < _items.length; i++){
			_selectedItem = _items[i];
			assertTrue(_controller.canEditItem());
			assertTrue(_controller.canRemoveItem());
			validateItemData(_selectedItem);
			assertTrue("Item is expected",expectedItems.contains(_selectedItem.getItem()));
			expectedItems.remove(_selectedItem.getItem());
		}
		
		assertTrue("All expected items should have been seen",expectedItems.isEmpty());
		
		// null checks
		_selectedItem = null;
		assertFalse(_controller.canEditItem());
		assertFalse(_controller.canRemoveItem());
		
		_selectedItem = selected;		
	}
	
	private void validateItemData(ItemData data){
		assertEquals(data.getItem().getBarcode().toString(), data.getBarcode());
		assertEquals(data.getItem().getEntryDate().getTime(), data.getEntryDate());
		Date expected = data.getItem().getExpirationDate().getTime();
		if (expected.equals(data.getItem().getEntryDate().getTime()))
			expected = null;
		assertEquals(expected, data.getExpirationDate());
		
		Container container = data.getItem().getContainer();
		if (container!= null){
			if (container instanceof StorageUnit){
				assertEquals(container.getName(), data.getStorageUnit());
				assertEquals("", data.getProductGroup());
			}
			else{
				assertEquals(container.getStorageUnit().getName(), data.getStorageUnit());
				assertEquals(container.getName(), data.getProductGroup());
			}
		}
		else{
			assertEquals("",data.getStorageUnit());
			assertEquals("",data.getProductGroup());
		}
	}
	
	
	public void validateContainers(){
		recurseValidateContainers(_root);
		// this only tests for current selection validity
		validateContextPanelForCurrentSelection();
	}
	
	private void validateContextPanelForCurrentSelection(){

		if (_selectedContainer == null){
			assertEquals("No selection, all context panel should be empty","",_contextPG);
			assertEquals("No selection, all context panel should be empty","",_contextSU);
			assertEquals("No selection, all context panel should be empty","",_contextSupply);

		}
		else if (_selectedContainer.getContainer() instanceof RootStorageUnit){
			assertEquals("RootStorageUnit => no pg","",_contextPG);
			assertEquals("RootStorageUnit => all","ALL",_contextSU);
			assertEquals("RootStorageUnit => no supply","",_contextSupply);
		}
		else if (_selectedContainer.getContainer() instanceof StorageUnit){
			assertEquals("StorageUnit => no pg","",_contextPG);
			assertEquals("StorageUnit => su name",_selectedContainer.getName(),_contextSU);
			assertEquals("StorageUnit => no supply","",_contextSupply);			
		}
		else{
			assertEquals("Product group context panel name",
					_selectedContainer.getName(),_contextPG);
			assertEquals("Product group context panel SU name",
					_selectedContainer.getContainer().getStorageUnit().getName(),_contextSU);
			if (((ProductGroup)_selectedContainer.getContainer()).getThreeMonthSupply().
					getQuantity() == 0)
				assertEquals("Product group context panel 3 month supply","",_contextSupply);
			else
				assertEquals("Product group context panel name",
						((ProductGroup)_selectedContainer.getContainer()).getThreeMonthSupply().
						toString(),
						_contextSupply);			
		}
	
	}
	
	public void recurseValidateContainers(ProductContainerData data){		
		validateProductContainerData(data);	// this also tests sorting
		validateContainerContextMenu(data);
		
		// recurse
		for(int i=0; i < data.getChildCount(); i++){
			recurseValidateContainers(data.getChild(i));
		}
		
	}


	private void validateContainerContextMenu(ProductContainerData data) {
		ProductContainerData selected = _selectedContainer;
		_selectedContainer = data;
		if (data.getContainer() instanceof RootStorageUnit){
			assertTrue(_controller.canRemoveItems());
			assertTrue(_controller.canAddStorageUnit());
		}
		else if (data.getContainer() instanceof StorageUnit){
			assertTrue(_controller.canAddProductGroup());
			assertTrue(_controller.canAddItems());
			assertTrue(_controller.canTransferItems());
			assertTrue(_controller.canEditStorageUnit());
			assertEquals(ContainerFacade.instance().canRemoveContainer(data.getContainer()),
					_controller.canDeleteStorageUnit());
		}
		else{
			assertTrue(_controller.canAddProductGroup());
			assertTrue(_controller.canEditProductGroup());
			assertEquals(ContainerFacade.instance().canRemoveContainer(data.getContainer()),
					_controller.canDeleteProductGroup());
		}
		
		_selectedContainer = selected;
	}
	
	private void validateProductContainerData(ProductContainerData data){
		assertEquals(data.getContainer().getName(), data.getName());
		Iterator<Container> children = data.getContainer().getChildContainers();
		
		// This validates that children are alphabetical
		for(int i=0; i < data.getChildCount(); i++){
			assertEquals(data.getChild(i).getContainer(),children.next());
		}
	}
	
	@Override
	public void displayInformationMessage(String message) {
		fail("Didn't think this was called" + message);		
	}

	@Override
	public void displayWarningMessage(String message) {
		fail("Didn't think this was called" + message);		
	}

	@Override
	public void displayErrorMessage(String message) {
		fail("Didn't think this was called" + message);		
	}

	@Override
	public void setProductContainers(ProductContainerData root) {
		_root = root;
		
	}

	@Override
	public void insertProductContainer(ProductContainerData parent,
			ProductContainerData newContainer, int index) {
		parent.insertChild(newContainer, index);
		
	}

	@Override
	public void selectProductContainer(ProductContainerData container) {
		_selectedContainer = container;
		
	}

	@Override
	public ProductContainerData getSelectedProductContainer() {
		return _selectedContainer;
	}

	@Override
	public void deleteProductContainer(ProductContainerData container) {
		getParent(_root,container).deleteChild(container);
		
	}
	
	private ProductContainerData getParent(ProductContainerData possibleparent, ProductContainerData child){
		if(possibleparent.getContainer() == child.getContainer().getParent()){
			return possibleparent;
		}
		for(int i=0; i < possibleparent.getChildCount(); i++){
			ProductContainerData parent = getParent(possibleparent.getChild(i), child);
			if (parent != null)
				return parent;
		}	
		return null;
	}

	@Override
	public void renameProductContainer(ProductContainerData renamedContainer,
			String newName, int newIndex) {
		getParent(_root,renamedContainer).renameChild(renamedContainer, newName, newIndex);
	}

	@Override
	public void setContextUnit(String value) {
		_contextSU = value;
		
	}

	@Override
	public void setContextGroup(String value) {
		_contextPG = value;
		
	}

	@Override
	public void setContextSupply(String value) {
		_contextSupply = value;
		
	}

	@Override
	public void setProducts(ProductData[] products) {
		_products = products;
		
	}

	@Override
	public ProductData getSelectedProduct() {
		return _selectedProduct;
	}

	@Override
	public void selectProduct(ProductData product) {
		_selectedProduct = product;
		
	}

	@Override
	public void setItems(ItemData[] items) {
		_items = items;
		
	}

	@Override
	public ItemData getSelectedItem() {
		return _selectedItem;
	}

	@Override
	public void selectItem(ItemData item) {
		_selectedItem = item;		
	}

	@Override
	public void displayAddStorageUnitView() {
		if(_cancel)
			return;
		try {
			ContainerFacade.instance().addStorageUnit(_name);
		} catch (IllegalAddException | SaveException e) {
			fail("oops");
		}
	}

	@Override
	public void displayAddProductGroupView() {
		if (_cancel)
			return;
		try {
			ContainerFacade.instance().addProductGroup(_selectedContainer.getContainer(), 
					_name, _amount, _unit);
		} catch (IllegalAddException | NotFoundException | SaveException e) {
			fail("oops");
		}
		
	}

	@Override
	public void displayAddItemBatchView() {
		if (_cancel)
			return;
		
		
			try {
				if (_name != null){
					Product p = new Product(_barcode,_name,"1","count",0,0);
					ProductFacade.instance().addProduct(p);
					ItemFacade.instance().createItems(ProductFacade.instance().getProduct(_barcode),
							_selectedContainer.getContainer(), 1, 
							DateUtils.formatDate(DateUtils.currentDate()));
				}
				else{
					ItemFacade.instance().createItems(_selectedProduct.getProduct(),
							_selectedContainer.getContainer(), 1, 
							DateUtils.formatDate(DateUtils.currentDate()));			
				}
			
			} catch (ModelException e) {
				fail("Oops");
			}

		
	}

	@Override
	public void displayTransferItemBatchView() {
		if (_cancel)
			return;
		try {
			ItemFacade.instance().transferItem(ItemFacade.instance().getItem("400000000008"),
					_selectedContainer.getContainer());
		} catch (IllegalAddException | NotFoundException e) {
			fail("oops " + e.getMessage());
		} catch (SaveException e){
			e.printStackTrace();
			fail("SaveException");
		}
		
	}

	@Override
	public void displayRemoveItemBatchView() {
		if (_cancel)
			return;
		try {
			ItemFacade.instance().removeItem(_items[0].getItem());
		} catch (IllegalRemoveException | NotFoundException e) {
			fail("oops");
		} catch (SaveException e){
			e.printStackTrace();
			fail("SaveException");
		}
		
	}

	@Override
	public void displayEditStorageUnitView() {
		if (_cancel)
			return;
		try {
			ContainerFacade.instance().renameContainer(_selectedContainer.getContainer(), _name);
		} catch (IllegalEditException | NotFoundException | SaveException e) {
			fail("oops");
		}
			
					
		
	}

	@Override
	public void displayEditProductGroupView() {
		if (_cancel)
			return;
		try {
			ContainerFacade.instance().renameContainer(_selectedContainer.getContainer(), _name);
		} catch (IllegalEditException | NotFoundException | SaveException e) {
			fail("oops");
		}
		try {
			ContainerFacade.instance().setThreeMonthSupply(_selectedContainer.getContainer(),
					_amount, _unit);
		} catch (IllegalArgumentException | SaveException e) {
			fail("oops");
		}
		
	}

	@Override
	public void displayEditProductView() {
		if (_cancel)
			return;
		
		Product p = new Product(_selectedProduct.getBarcode(),"changedProduct", "7.7", "grams", 0, 
				0);
		
		try {
			ProductFacade.instance().editProduct(_selectedProduct.getProduct(), p);
		} catch (Exception e) {
			fail("oops");
		}
		
	}

	@Override
	public void displayEditItemView() {
		if (_cancel)
			return;
		
		try {
			ItemFacade.instance().editItem(_selectedItem.getItem(), "01/04/2004");
		} catch (IllegalEditException | NotFoundException e) {
			fail("oops");
		} catch (SaveException e){
			e.printStackTrace();
			fail("SaveException");
		}
		
	}
	


}
